package com.qd.panda.service.wallet.user;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.math.Money;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.dto.ApiResult;
import com.cdqidi.dto.ApiResultWrapper;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.LockTemplate;
import com.cdqidi.util.SpringContextHolder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.qd.common.flow.constant.FlowConstants;
import com.qd.common.flow.domain.event.FlowTaskStateDTO;
import com.qd.common.panda.config.PandaParkConfigDTO;
import com.qd.common.panda.constant.PandaConstant;
import com.qd.common.panda.domain.entity.hk.HkArrearsRecordsDataReq;
import com.qd.common.panda.domain.entity.hk.HkPaymentInfoReq;
import com.qd.common.panda.domain.entity.msg.UserMsgDTO;
import com.qd.common.panda.domain.entity.stroke.PayParamDTO;
import com.qd.common.panda.domain.entity.wallet.user.*;
import com.qd.common.sys.domain.login.LoginUser;
import com.qd.common.sys.util.SecurityUtils;
import com.qd.panda.model.*;
import com.qd.panda.service.hk.HkParkOrderService;
import com.qd.panda.service.hk.HkService;
import com.qd.panda.service.msg.UserMsgService;
import com.qd.panda.service.plate.UserPlateRelationService;
import com.qd.panda.service.stroke.DisplayUtil;
import com.qd.panda.service.stroke.UserStrokeHolderService;
import com.qd.panda.service.wallet.plan.PlanService;
import com.qd.panda.service.wallet.publish.PlanPublishListService;
import com.qd.panda.service.wallet.publish.PlanPublishService;
import com.qd.pay.config.PayConstant;
import com.qd.pay.domain.OrderDTO;
import com.qd.pay.service.order.OrderHolderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author sjk
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class WalletService {

    private final UserWalletService userWalletService;
    private final UserWalletRechargeLogService userWalletRechargeLogService;
    private final UserWalletConsumptionLogService userWalletConsumptionLogService;
    private final UserWalletRefundApplyService userWalletRefundApplyService;
    private final UserWalletRefundApplyOrderService userWalletRefundApplyOrderService;
    private final UserWalletRefundLogService userWalletRefundLogService;
    private final UserPlateRelationService userPlateRelationService;
    private final PlanPublishService planPublishService;
    private final PlanPublishListService planPublishListService;
    private final PlanService planService;
    private final OrderHolderService orderHolderService;
    private final ObjectMapper objectMapper;
    private final HkService hkService;
    private final HkParkOrderService hkParkOrderService;
    private final PlatformTransactionManager transactionManager;
    private final UserMsgService userMsgService;

    @Resource
    private PandaParkConfigDTO pandaParkConfig;

    @Transactional(rollbackFor = Exception.class)
    public void updateApprovalStatus(FlowTaskStateDTO flowTaskStateDTO) {
        String bid = flowTaskStateDTO.getBid();
        Integer approvalStatus = flowTaskStateDTO.getApprovalStatus();
        UserWalletRefundApplyDTO userWalletRefundApplyDTO = Optional.ofNullable(userWalletRefundApplyService.getByIdDto(bid)).orElseThrow(() -> new ApiException("申请ID值错误"));
        userWalletRefundApplyDTO.setApprovalStatus(approvalStatus);
        userWalletRefundApplyDTO.setCompletionTime(flowTaskStateDTO.getApprovalTime());
        userWalletRefundApplyService.update(userWalletRefundApplyDTO, false);

        if (approvalStatus.equals(FlowConstants.APPROVAL_STATUS_1)) {
            if (userWalletRefundApplyDTO.getRefundMethod() == 1) {
                //线上退款
                List<UserWalletRefundApplyOrder> list = userWalletRefundApplyOrderService.getListByRequestId(bid, DisplayUtil.REFUND_STATUS_0);
                if (list.isEmpty()) {
                    throw new ApiException("没有可以退款的订单");
                }
                userWalletRefundApplyService.refundRequests(flowTaskStateDTO.getApprovalTime(), userWalletRefundApplyDTO.getApplicant(), list);
                list.clear();
            } else if (userWalletRefundApplyDTO.getRefundMethod() == 2) {
                //线下退款
                userWalletRefundApplyService.buildExtendsJson(flowTaskStateDTO, userWalletRefundApplyDTO);
            } else {
                throw new ApiException("退款方式值错误");
            }
            //计算钱包费用
            UserWalletDTO userWalletDTO = operatorUserWallet(userWalletRefundApplyDTO.getApplicant(), flowTaskStateDTO.getApprovalTime());
            userWalletDTO.freeData();
        } else {
            List<UserWalletRefundApplyOrder> list = userWalletRefundApplyOrderService.getListByRequestId(userWalletRefundApplyDTO.getRequestId(), DisplayUtil.REFUND_STATUS_0);
            if (!list.isEmpty()) {
                for (UserWalletRefundApplyOrder userWalletRefundApplyOrder : list) {
                    userWalletRefundApplyOrder.setRefundStatus(DisplayUtil.REFUND_STATUS_2);
                }
                userWalletRefundApplyOrderService.updateBatchIds(list);
                list.clear();
            }
        }
//        sendUserMsg(flowTaskStateDTO, userWalletRefundApplyDTO);
        userWalletRefundApplyDTO.freeData();
    }

    private void sendUserMsg(FlowTaskStateDTO flowTaskStateDTO, UserWalletRefundApplyDTO userWalletRefundApplyDTO) {
        String msg = "钱包退款申请";
        if (flowTaskStateDTO.getApprovalStatus().equals(FlowConstants.APPROVAL_STATUS_1)) {
            msg += "已通过";
        } else {
            msg += "未通过";
            if (StringUtils.hasLength(flowTaskStateDTO.getApprovalResult())) {
                msg += ",原因: " + flowTaskStateDTO.getApprovalResult();
            }
        }
        UserMsgDTO userMsgDTO = new UserMsgDTO();
        userMsgDTO.setMsgType(PandaConstant.MSG_TYPE_14);
        userMsgDTO.setUserId(userWalletRefundApplyDTO.getApplicant());
        userMsgDTO.setAddTime(flowTaskStateDTO.getApprovalTime());
        userMsgDTO.setNote(msg);
        userMsgDTO.setBid(userWalletRefundApplyDTO.getRequestId());
        userMsgDTO.setCanRead(0);
        userMsgService.save(userMsgDTO);
        userMsgDTO.freeData();
    }

    @Transactional(rollbackFor = Exception.class)
    public PayParamDTO recharge(UserWalletRechargeDTO dto) {
        String rechargeAmountStr = dto.getRechargeAmount();
        Integer rechargeAmount = null;
        if (StringUtils.hasLength(rechargeAmountStr)) {
            try {
                rechargeAmount = Integer.parseInt(rechargeAmountStr);
            } catch (Exception e) {
                throw new ApiException("请输入正确的金额");
            }
        }
//        if (null != rechargeAmount) {
//            if (rechargeAmount > 500) {
//                throw new ApiException("单笔充值金额不能大于500");
//            }
//            if (rechargeAmount % 10 > 0) {
//                throw new ApiException("充值金额只能是10的倍数");
//            }
//        }
        PlanPublish planPublish = Optional.ofNullable(planPublishService.getById(dto.getPublishId())).orElseThrow(() -> new ApiException("套餐发布ID值错误"));
        if (planPublish.getEnable().equals(ConstantDto.SF0)) {
            throw new ApiException("当前充值已停用");
        }
        List<PlanPublishList> list = planPublishListService.getListByPublishId(dto.getPublishId());
        if (list.isEmpty()) {
            throw new ApiException("当前充值已停用");
        }
        List<String> planCodes = list.stream().map(PlanPublishList::getPlanCode).collect(Collectors.toList());
        if (!planCodes.contains(dto.getPlanCode())) {
            throw new ApiException("当前充值不存在");
        }
        Plan plan = Optional.ofNullable(planService.getById(dto.getPlanCode())).orElseThrow(() -> new ApiException("套餐编码值错误"));
        LocalDateTime now = LocalDateTime.now();
        UserWalletRechargeLogDTO userWalletRechargeLog = new UserWalletRechargeLogDTO();
        userWalletRechargeLog.setOrderId(IdWorker.getIdStr());
        userWalletRechargeLog.setRechargeTime(now);
        userWalletRechargeLog.setPayStatus(DisplayUtil.PAY_STATUS_0);
        userWalletRechargeLog.setUserId(dto.getUserId());
        userWalletRechargeLog.setPlanCode(dto.getPlanCode());
        userWalletRechargeLog.setPublishId(dto.getPublishId());
        if (null == plan.getPlateAmount() && null == rechargeAmount) {
            throw new ApiException("请输入金额");
        }
        if (null == rechargeAmount) {
            rechargeAmount = plan.getPlateAmount();
        }
        Integer giftRatio = plan.getGiftRatio();
        Integer startAmount = Optional.ofNullable(plan.getStartAmount()).orElse(0);
        int giveAmount = 0;
        if (null != giftRatio) {
            if (rechargeAmount >= startAmount) {
                giveAmount = new Money(rechargeAmount).multiply(giftRatio).divide(100).getAmount().intValue();
            }
        }
        userWalletRechargeLog.setGiveAmount(new BigDecimal(String.valueOf(giveAmount)));
        userWalletRechargeLog.setPayAmount(new BigDecimal(String.valueOf(rechargeAmount)));
        userWalletRechargeLog.setAllAmount(userWalletRechargeLog.getGiveAmount().add(userWalletRechargeLog.getPayAmount()));
        userWalletRechargeLog.setRechargeType(PandaConstant.RECHARGE_TYPE_1);
        userWalletRechargeLogService.save(userWalletRechargeLog);

        if (SpringContextHolder.getActiveProfile().equals(SpringContextHolder.PROFILE_DEV)) {
            return null;
        }

        PayParamDTO order = createOrder(userWalletRechargeLog.getPayAmount(), userWalletRechargeLog.getOrderId());

        planPublish.freeData();
        userWalletRechargeLog.freeData();
        plan.freeData();
        list.clear();
        return order;
    }

    private PayParamDTO createOrder(BigDecimal payMoney, String bid) {
        if (!StringUtils.hasLength(pandaParkConfig.getParkPartner())) {
            throw new ApiException("配置停车支付主商户");
        }
        if (!StringUtils.hasLength(pandaParkConfig.getWalletSubPartner())) {
            throw new ApiException("配置钱包支付子商户");
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        OrderDTO orderDto = new OrderDTO();
        orderDto
                .setThirdPartyOrder(bid).setPayAmount(payMoney)
                .setNotifyUrl(pandaParkConfig.getDomain() + "/gy-panda-park/app/userStroke/notify/payAfter")
                .setType(PayConstant.ORDER_TYPE_2).setAppId(pandaParkConfig.getDefaultMiniProgramAppId())
                .setPartner(pandaParkConfig.getParkPartner()).setSubPartner(pandaParkConfig.getWalletSubPartner());
        orderDto.setPersonId(loginUser.getUserId());
        orderDto.setOpenid(loginUser.getUser().getAppUserExtend().getOpenid());
        log.info("bid: {},金额: {}", bid, orderDto.getPayAmount());
        ObjectNode attachObjectNode = objectMapper.createObjectNode();
        orderDto.setBody("钱包").setSubject("钱包充值");
        attachObjectNode.put("orderType", DisplayUtil.ORDER_TYPE_8);
        orderDto.setAttach(attachObjectNode);
        ObjectNode child = objectMapper.createObjectNode();
        ObjectNode wxLite = objectMapper.createObjectNode();
        wxLite.put(UserStrokeHolderService.AMOUNT, orderDto.getPayAmount().doubleValue());
        wxLite.put("sub_appid", pandaParkConfig.getDefaultMiniProgramAppId());
        wxLite.put("sub_openid", orderDto.getOpenid());
        child.set("wx_lite", objectMapper.createArrayNode().add(wxLite));
        orderDto.setChannelDetails(child);

        Map<String, String> params = orderHolderService.createOrder(orderDto);
        if (params.isEmpty()) {
            throw new ApiException("获取支付参数异常");
        }
        PayParamDTO payParamDTO = new PayParamDTO();
        payParamDTO.setAppId(pandaParkConfig.getDefaultMiniProgramAppId()).setNonceStr(params.get("nonceStr")).setPrepayId(params.get("package")).setPaySign(params.get("paySign")).setSignType("MD5").setTimeStamp(params.get("timeStamp")).setThirdPartyOrder(bid);
        payParamDTO.setPayAmount(orderDto.getPayAmount().stripTrailingZeros().toPlainString());
        return payParamDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    public ApiResultWrapper<Object> payError(String bid, Integer payStatus) {
        UserWalletRechargeLogDTO userWalletRechargeLogDTO = Optional.ofNullable(userWalletRechargeLogService.getByIdDto(bid)).orElseThrow(() -> new ApiException("业务ID值错误"));
        if (userWalletRechargeLogDTO.getPayStatus().equals(payStatus)) {
            return ApiResult.error("请勿重复操作");
        }
        if (userWalletRechargeLogDTO.getPayStatus().equals(DisplayUtil.PAY_STATUS_1)) {
            return ApiResult.success("没有权限操作");
        }
        userWalletRechargeLogDTO.setPayStatus(payStatus);
        userWalletRechargeLogService.update(userWalletRechargeLogDTO);
        userWalletRechargeLogDTO.freeData();
        return ApiResult.success();
    }

    public void updateOrderStatus(String userId, String bid, Integer payStatus) {
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition(DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW));
//        RedissonLockTemplate.execute(userId, () -> {
        LockTemplate.execute(userId, () -> {
            UserWalletRechargeLogDTO userWalletRechargeLogDTO = userWalletRechargeLogService.getByIdDto(bid);
            if (userWalletRechargeLogDTO.getPayStatus().equals(DisplayUtil.PAY_STATUS_1) || userWalletRechargeLogDTO.getPayStatus().equals(DisplayUtil.PAY_STATUS_2)) {
                return null;
            }
            userWalletRechargeLogDTO.setPayStatus(payStatus);
            userWalletRechargeLogService.update(userWalletRechargeLogDTO);

            UserWalletDTO userWalletDTO = operatorUserWallet(userId, LocalDateTime.now());

            userWalletDTO.freeData();
            userWalletRechargeLogDTO.freeData();
            return null;
        });
        transactionManager.commit(status);
    }


    //    @Transactional(rollbackFor = Exception.class)
    public UserWalletDTO operatorUserWallet(String userId, LocalDateTime now) {
        boolean isUpdate = true;
        UserWalletDTO userWalletDTO = userWalletService.getByIdDto(userId);
        if (null == userWalletDTO) {
            userWalletDTO = new UserWalletDTO();
            userWalletDTO.setUserId(userId);
            isUpdate = false;
        }
        //消费记录
        UserWalletConsumptionLogDTO userWalletConsumptionLogDTO = userWalletConsumptionLogService.sumConsumptionAmountByUserId(userId);
        //充值记录
        UserWalletRechargeLog userWalletRechargeLog = userWalletRechargeLogService.sumRechargeLogByUserId(userId);
        //退款记录
        UserWalletRefundApply userWalletRefundApply = userWalletRefundApplyService.sumRefundByUserId(userId);

        //剩余金额
        BigDecimal remainingAmount = new Money(userWalletRechargeLog.getAllAmount().toPlainString())
                .subtract(new Money(userWalletConsumptionLogDTO.getConsumptionAmount().toPlainString()))
                .subtract(new Money(userWalletRefundApply.getActualRefundGiveAmount().toPlainString()))
                .subtract(new Money(userWalletRefundApply.getActualRefundAmount().toString()))
                .getAmount();
        //剩余赠送金额
        BigDecimal remainingGiveAmount = new Money(userWalletRechargeLog.getGiveAmount().toString())
                .subtract(new Money(userWalletConsumptionLogDTO.getWalletGiveAmount().toString()))
                .subtract(new Money(userWalletRefundApply.getActualRefundGiveAmount().toString()))
                .getAmount();
        //剩余充值金额
        BigDecimal remainingRechargeAmount = new Money(userWalletRechargeLog.getPayAmount().toString())
                .subtract(new Money(userWalletConsumptionLogDTO.getWalletAmount().toString()))
                .subtract(new Money(userWalletRefundApply.getActualRefundAmount().toString()))
                .getAmount();
        userWalletDTO.setRemainingAmount(remainingAmount);
        userWalletDTO.setRemainingGiveAmount(remainingGiveAmount);
        userWalletDTO.setRemainingRechargeAmount(remainingRechargeAmount);
        if (isUpdate) {
            userWalletDTO.setUpdateTime(now);
            userWalletService.update(userWalletDTO);
        } else {
            userWalletDTO.setCardNumber(createCardNumber(0));
            userWalletDTO.setAddTime(now);
            userWalletService.save(userWalletDTO);
        }
        return userWalletDTO;
    }

    private String createCardNumber(int i) {
        if (i > 100) {
            throw new ApiException("生成卡号异常");
        }
        String cardNumber = RandomUtil.randomNumbers(16);
        UserWallet userWallet = userWalletService.getUniqueByCardNumber(cardNumber);
        if (null != userWallet) {
            return createCardNumber(i + 1);
        }
        return cardNumber;
    }

    @Transactional(rollbackFor = Exception.class)
    public PayParamDTO payment(LoginUser loginUser, HkPaymentInfoReq req) {
        LocalDateTime now = LocalDateTime.now();
        UserWalletDTO userWalletDTO = userWalletService.getByIdDto(loginUser.getUserId());
        if (null == userWalletDTO) {
            throw new ApiException("用户钱包余额不足");
        }
        if (userWalletRefundApplyService.isRunning(loginUser.getUserId())) {
            throw new ApiException("钱包存在退款操作,不能使用");
        }
        if (!SpringContextHolder.getActiveProfile().equals(SpringContextHolder.PROFILE_DEV)) {
            checkPlate(loginUser, req.getPlateNo());
        }
        //剩余金额
        BigDecimal remainingAmount = userWalletDTO.getRemainingAmount();
        //剩余充值金额
        BigDecimal remainingRechargeAmount = userWalletDTO.getRemainingRechargeAmount();
        //剩余剩余赠送金额
        BigDecimal remainingGiveAmount = userWalletDTO.getRemainingGiveAmount();
        //停车费用
        Money payMoney = new Money(0, req.getPayMoney());
        BigDecimal consumptionAmount = payMoney.getAmount();
        log.info("停车费用: {},剩余金额: {},剩余充值金额: {},剩余赠送金额: {}", consumptionAmount, remainingAmount, remainingRechargeAmount, remainingGiveAmount);
        if (consumptionAmount.compareTo(remainingAmount) > 0) {
            throw new ApiException("钱包余额不足");
        }
        String bid = IdWorker.getIdStr();
        BigDecimal walletAmount;
        BigDecimal walletGiveAmount = new BigDecimal(0);

        if (remainingRechargeAmount.compareTo(consumptionAmount) >= 0) {
            walletAmount = consumptionAmount;
        } else {
            if (remainingRechargeAmount.compareTo(new BigDecimal(0)) == 0) {
                walletAmount = new BigDecimal("0");
                walletGiveAmount = consumptionAmount;
            } else {
                walletAmount = remainingRechargeAmount;
                walletGiveAmount = payMoney.subtract(new Money(walletAmount.toString())).getAmount();
            }
            if (walletGiveAmount.compareTo(remainingGiveAmount) > 0) {
                throw new ApiException("钱包赠送余额不足");
            }
        }
        UserWalletConsumptionLogDTO userWalletConsumptionLogDTO = new UserWalletConsumptionLogDTO();
        userWalletConsumptionLogDTO.setConsumptionLogId(bid);
        userWalletConsumptionLogDTO.setUserId(loginUser.getUserId());
        userWalletConsumptionLogDTO.setConsumptionTime(now);
        userWalletConsumptionLogDTO.setUserId(userWalletConsumptionLogDTO.getUserId());
        userWalletConsumptionLogDTO.setOrderLogId(bid);
        userWalletConsumptionLogDTO.setMsgType(PandaConstant.MSG_TYPE_2);
        userWalletConsumptionLogDTO.setMsgTypeChildId(PandaConstant.HK_ORDER_TYPE_1 + "");
        userWalletConsumptionLogDTO.setConsumptionAmount(consumptionAmount);
        userWalletConsumptionLogDTO.setWalletAmount(walletAmount);
        userWalletConsumptionLogDTO.setWalletGiveAmount(walletGiveAmount);
        userWalletConsumptionLogService.save(userWalletConsumptionLogDTO);
        userWalletConsumptionLogDTO.freeData();
        hkService.createOrder(req, loginUser, bid, walletAmount, walletGiveAmount, now);
        //更新用户钱包信息
        operatorUserWallet(loginUser.getUserId(), now);
        userWalletDTO.freeData();
        return new PayParamDTO().setThirdPartyOrder(bid);
    }

    @Transactional(rollbackFor = Exception.class)
    public PayParamDTO paymentBatch(LoginUser loginUser, HkArrearsRecordsDataReq data) {
        if (userWalletRefundApplyService.isRunning(loginUser.getUserId())) {
            throw new ApiException("钱包存在退款操作,不能使用");
        }
        List<HkArrearsRecordsDataReq.HkArrearsRecords> list = data.getData();
        if (null == list || list.isEmpty()) {
            throw new ApiException("请选择要支付的订单");
        }
        if (!SpringContextHolder.getActiveProfile().equals(SpringContextHolder.PROFILE_DEV)) {
            hkService.checkOrder(data, list);
        }

        UserWalletDTO userWalletDTO = userWalletService.getByIdDto(loginUser.getUserId());
        if (null == userWalletDTO) {
            throw new ApiException("用户钱包余额不足");
        }
        //剩余金额
        BigDecimal remainingAmount = userWalletDTO.getRemainingAmount();
        //剩余充值金额
        Money remainingRechargeAmount = new Money(userWalletDTO.getRemainingRechargeAmount());
        //剩余剩余赠送金额
        Money remainingGiveAmount = new Money(userWalletDTO.getRemainingGiveAmount());
        //总的欠费金额
        Money all = new Money();
        Set<String> plateSet = new HashSet<>();
        for (HkArrearsRecordsDataReq.HkArrearsRecords hkArrearsRecords : list) {
            all = all.add(new Money(0, hkArrearsRecords.getArrearsFee()));
            plateSet.add(hkArrearsRecords.getPlateNo());
        }
        if (!SpringContextHolder.getActiveProfile().equals(SpringContextHolder.PROFILE_DEV)) {
            checkPlate(loginUser, plateSet);
        }
        log.info("总的订单欠费金额: {}", all);
        //总的欠费金额
        BigDecimal allAmount = all.getAmount();
        if (allAmount.compareTo(remainingAmount) > 0) {
            log.info("钱包余额不足,钱包余额: {},订单金额: {}", remainingAmount, allAmount);
            throw new ApiException("用户钱包余额不足,请充值");
        }
        List<HkParkOrder> orderList = new ArrayList<>(list.size());
        List<UserWalletConsumptionLog> consumptionLogList = new ArrayList<>(list.size());
        String bid = IdWorker.getIdStr();
        LocalDateTime now = LocalDateTime.now();


        for (HkArrearsRecordsDataReq.HkArrearsRecords req : list) {
            //钱包支付金额
            Money walletAmount;
            //钱包赠送支付金额
            Money walletGiveAmount = new Money("0");
            Money arrearsFee = new Money(0, req.getArrearsFee());
            BigDecimal consumptionAmount = arrearsFee.getAmount();
            if (hkParkOrderService.paySuccess(req.getBillCode())) {
                log.error("欠费补交,当前订单已经支付成功,订单编号: {}", req.getBillCode());
                throw new ApiException("当前订单已经支付成功，请勿重复支付");
            }
            if (remainingRechargeAmount.compareTo(arrearsFee) >= 0) {
                walletAmount = arrearsFee;
                remainingRechargeAmount = remainingRechargeAmount.subtract(walletAmount);
            } else {
                if (remainingRechargeAmount.compareTo(new Money(0)) == 0) {
                    walletAmount = new Money("0");
                    walletGiveAmount = arrearsFee;
                } else {
                    walletAmount = remainingRechargeAmount;
                    walletGiveAmount = arrearsFee.subtract(walletAmount);
                }
                if (walletGiveAmount.compareTo(remainingGiveAmount) > 0) {
                    log.error("钱包赠送余额不足，钱包赠送支付金额： {}，剩余赠送金额： {}", walletGiveAmount, remainingGiveAmount);
                    throw new ApiException("钱包赠送余额不足");
                }
                remainingRechargeAmount = remainingRechargeAmount.subtract(walletAmount);
                remainingGiveAmount = remainingGiveAmount.subtract(walletGiveAmount);

            }
//            log.info("订单金额: {},钱包支付金额: {},钱包赠送支付金额: {},钱包充值余额： {}，钱包赠送余额: {}",arrearsFee,walletAmount,walletGiveAmount,remainingRechargeAmount,remainingGiveAmount);
            HkParkOrder hkParkOrder = hkService.createOrder(req, bid, now);
            hkParkOrder.setOrderLogId(IdWorker.getIdStr());
            hkParkOrder.setUserId(loginUser.getUserId());
            hkParkOrder.setPhone(loginUser.getUser().getAppUserExtend().getMobile());
            hkParkOrder.setPayStatus(DisplayUtil.PAY_STATUS_1);
            hkParkOrder.setPayMethod(PandaConstant.PAY_METHOD_WALLET);
            hkParkOrder.setWalletAmount(walletAmount.getAmount());
            hkParkOrder.setWalletGiveAmount(walletGiveAmount.getAmount());
            orderList.add(hkParkOrder);

            UserWalletConsumptionLog userWalletConsumptionLog = new UserWalletConsumptionLog();
            userWalletConsumptionLog.setOrderLogId(hkParkOrder.getOrderLogId());
            userWalletConsumptionLog.setUserId(loginUser.getUserId());
            userWalletConsumptionLog.setConsumptionTime(now);
            userWalletConsumptionLog.setUserId(userWalletConsumptionLog.getUserId());
            userWalletConsumptionLog.setOrderLogId(hkParkOrder.getOrderLogId());
            userWalletConsumptionLog.setMsgType(PandaConstant.MSG_TYPE_2);
            userWalletConsumptionLog.setMsgTypeChildId(PandaConstant.HK_ORDER_TYPE_2 + "");
            userWalletConsumptionLog.setConsumptionAmount(consumptionAmount);
            userWalletConsumptionLog.setWalletAmount(walletAmount.getAmount());
            userWalletConsumptionLog.setWalletGiveAmount(walletGiveAmount.getAmount());
            consumptionLogList.add(userWalletConsumptionLog);
        }

        List<HkParkOrder> sendList = BeanUtil.copyToList(orderList, HkParkOrder.class, CopyOptions.create());

        hkParkOrderService.saveBatch(orderList);

        userWalletConsumptionLogService.saveBatch(consumptionLogList);
        operatorUserWallet(loginUser.getUserId(), now);
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCompletion(int status) {
                if (TransactionSynchronization.STATUS_COMMITTED == status) {
                    log.info("钱包欠费支付，通知海康");
                    for (HkParkOrder hkParkOrder : sendList) {
                        hkService.sendMq(hkParkOrder);
                    }
                    sendList.clear();
                }
            }
        });
        orderList.clear();
        consumptionLogList.clear();

        return new PayParamDTO().setThirdPartyOrder(bid);
    }

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void updateRefundStatus(UserWalletRefundLogDTO userWalletRefundLogDTO) {
        userWalletRefundLogService.update(userWalletRefundLogDTO);

        UserWalletRefundApplyOrderDTO userWalletRefundApplyOrderDTO = userWalletRefundApplyOrderService.getByIdDto(userWalletRefundLogDTO.getRefundId());
        userWalletRefundApplyOrderDTO.setRefundStatus(userWalletRefundLogDTO.getRefundStatus());
        userWalletRefundApplyOrderService.update(userWalletRefundApplyOrderDTO);

        UserWalletRefundApplyDTO userWalletRefundApplyDTO = userWalletRefundApplyService.getByIdDto(userWalletRefundApplyOrderDTO.getRequestId());

        List<UserWalletRefundApplyOrder> list = userWalletRefundApplyOrderService.getListByRequestId(userWalletRefundApplyOrderDTO.getRequestId(), null);
        //是否计算钱包剩余金额
        boolean calWallet = true;
        if (null == list) {
            userWalletRefundApplyDTO.setActualRefundAmount(new BigDecimal("0.00"));
            userWalletRefundApplyDTO.setActualRefundGiveAmount(userWalletRefundApplyDTO.getActualRefundAmount());
            calWallet = false;
        } else {
            Money actualRefundAmount = new Money("0.00");
            for (UserWalletRefundApplyOrder userWalletRefundApplyOrder : list) {
                if (userWalletRefundApplyOrder.getRefundStatus().equals(DisplayUtil.REFUND_STATUS_0)) {
                    calWallet = false;
                }
                if (userWalletRefundApplyOrder.getRefundStatus().equals(DisplayUtil.REFUND_STATUS_0) || userWalletRefundApplyOrder.getRefundStatus().equals(DisplayUtil.REFUND_STATUS_1)) {
                    actualRefundAmount = actualRefundAmount.add(new Money(userWalletRefundApplyOrder.getRefundAmount()));
                }
            }
            userWalletRefundApplyDTO.setActualRefundAmount(actualRefundAmount.getAmount());
            if (actualRefundAmount.compareTo(new Money("0.00")) == 0) {
                userWalletRefundApplyDTO.setActualRefundGiveAmount(userWalletRefundApplyDTO.getActualRefundAmount());
            }
            list.clear();
        }
        userWalletRefundApplyService.update(userWalletRefundApplyDTO, false);
        if (calWallet) {
            //计算钱包剩余金额
            UserWalletDTO userWalletDTO = operatorUserWallet(userWalletRefundApplyDTO.getApplicant(), LocalDateTime.now());
            userWalletDTO.freeData();
        }
    }


    private void checkPlate(LoginUser loginUser, String plateNo) {
        checkPlate(loginUser, Set.of(plateNo));
    }

    private void checkPlate(LoginUser loginUser, Set<String> plateSet) {
        List<UserPlateRelation> list = userPlateRelationService.getUserPlateRelationByUserId(loginUser.getUserId());
        if (list.isEmpty()) {
            throw new ApiException("请绑定车牌后在试");
        }
        Set<String> plateNumbers = list.stream().map(UserPlateRelation::getPlateNumber).collect(Collectors.toSet());
        for (String plateNumber : plateSet) {
            if (!CollUtil.contains(plateNumbers, plateNumber)) {
                throw new ApiException("请绑定当前车牌[" + plateNumber + "]后使用钱包支付");
            }
        }
    }
}
